#pragma once

#include "..\\ExternalTools\\ExternalTools.h"

#include "..\\Loirey\\loirey_GLOBAL.h"
#include "..\\Loirey\\loirey_BasicStructure.h"

#include "..\\Classification.Base\cl_base_Data.h"
#include "..\\Classification.Base\cl_base_BinaryClassification.h"

#include "cl_boost_AdaBoost.h"

using namespace loirey;

class CCascadedAdaBoostParametersConfig
{
public:
	int MaxLayerAmount;
	CSimpleTypeArray<CAdaBoostTrainingEndCondition> PerLayerTrainingEndCondition;
	CAdaBoostTrainingEndCondition DefaultLayerTrainingCondition;
	int MaxTrainPosExampleAmount;
	int MinTrainPosExampleAmount;
	int MaxTrainNegExampleAmount;
	int MinTrainNegExampleAmount;

	CAdaBoostParameterConfig AdaBoostConfig;
	int TrainFeatureGroupAmount;

	string strPN_ForTrain;
	int FeatureMemoryUsage_Pos_Train;
	int FeatureMemoryUsage_Pos_Val;
	int FeatureMemoryUsage_Train;
	int FeatureMemoryUsage_Val;
	string strFN_PosFeatureData_Train;
	string strFN_PosFeatureData_Val;
	string strFN_TempFeatureData_Train;
	string strFN_TempFeatureData_Val;

	int OutputROC_SamplingCount;
	bool OutputROC_fUseLogScale;
	double OutputROC_MinFPR;
	double OutputROC_MaxFPR;

public:
	CCascadedAdaBoostParametersConfig();
	void InitLayerTrainingEndConditionList(string strFN_Config);
};

class CDetailedBinaryCascadeClassifyResult
{
private:
	int _size;
public:
	CBinaryClassificationResult_ByPrediction Performance;
	int TestCaseAmount;
	int* resPerCaseRealFlag;
	double* resPerCaseResult;
	int* resPerCasePrediction;
	int* resPerCaseExitLayer;

public:
	void myRelease();
	CDetailedBinaryCascadeClassifyResult();
	~CDetailedBinaryCascadeClassifyResult();

	void myInit(int MaxTestCaseAmount);
	void Clear();
	void NewTest(int RealFlag, double Result, int Prediction, int ExitLayer, double Weight);
	void Analyse();
};

class CCascadedAdaBoostClassifier : public CBinaryClassifier
{
public:
	int LayerAmount;
	vector<CAdaBoostClassifier> rgLayer;
	int total_trained_weak_learner_amount;
public:
	int TestLayerAmount;
	//bool fSaveClassifyingHistory;
	//int ClassifiedExampleAmount;
	//int InHistoryLayerAmountTested;
	//CSimpleTypeArray<double> ClassifyingHistory_Confidence;

public:
	CCascadedAdaBoostClassifier();
	virtual ~CCascadedAdaBoostClassifier() { }
public:
	bool InputFromStream(istream& inStream);
	void OutputToStream(ostream& outStream);
public:
	void FilterExampleList(
		CDataSetForClassification* pDataSet, CBinaryClassificationExampleList& TargetSignedExampleList,
		int LayerToStart, int LayerToFinish,
		CBinaryClassificationResult_ByPrediction& bcrP_cascade,
		CBinaryClassificationResult_ByPrediction& bcrP_backup,
		CBinaryClassificationResult_ByPrediction& bcrP_classify,
		CBinaryClassificationResult_ByConfidence& bcrC_backup,
		CBinaryClassificationResult_ByConfidence& bcrC_classify,
		double& time_cost, ostream& oLog);
public:
	void Train(
		CDataSetForBinaryClassification* pDataSet_Train, CBinaryClassificationExampleList& ExampleList_Train,
		CDataSetForBinaryClassification* pDataSet_Val, CBinaryClassificationExampleList& ExampleList_Val,
		CCascadedAdaBoostParametersConfig& CascadeConfig,
		ostream& oLog
		);
	void Train(
		string strFN_DstModel, int LayerToStartTraining, int LayerToStartClassification,
		CDataSetForBinaryClassification* pDataSet_Train, CBinaryClassificationExampleList& ExampleList_Train,
		CDataSetForBinaryClassification* pDataSet_Val, CBinaryClassificationExampleList& ExampleList_Val,
		CCascadedAdaBoostParametersConfig& CascadeConfig,
		ostream& oLog
		);
	void Train(
		string strFN_DstModel, int LayerToStartTraining, int LayerToStartClassification,
		CDataSetForBinaryClassification* pDataSet_Train, CBinaryClassificationExampleList& ExampleList_Train,
		CDataSetForBinaryClassification* pDataSet_Val, CBinaryClassificationExampleList& ExampleList_Val,
		CCascadedAdaBoostParametersConfig& CascadeConfig,
		ostream& oLog,
		CSimpleTypeArray<CBinaryClassificationExampleList>* pFilteredExampleList_Train,
		CSimpleTypeArray<CBinaryClassificationExampleList>* pFilteredExampleList_Val
		);
public:
	double GetMinConfidenceBound(int First_X_Layers = -1) const;
	double GetMaxConfidenceBound(int First_X_Layers = -1) const;
public:
	void SetAndClearTestingConfig(int TestLayerAmount, bool fSaveClassifyingHistory);
	//void ClearTestingHistogry();
protected:
	virtual void _Classify(CDataSetForClassification* pDataSet, int ExampleIndex, double& DstConfidence, int& DstPrediction);
public:
	int GetTotalWeakLearnerAmount(int CountingLayerAmount = -1) const;
public:
	void Classify(
		CDataSetForClassification* pDataSet, int ExampleIndex,
		int paraTestLayerAmount,
		double& DstConfidence, int& DstPrediction, int& resExitLayer
		);
	void Classify(
		CDataSetForClassification* pDataSet, int ExampleIndex,
		int paraTestLayerAmount, int& ExitLayer,
		CSimpleTypeArray<double>& DstConfidenceList);
	//void Classify(
	//	CDataSetForClassification* pDataSet, int ExampleIndex,
	//	int paraTestLayerAmount,
	//	vector<double>& resRgConfidence, vector<int>& resRgPrediction, vector<int>& resRgExitLayer
	//	);
	//void Classify(
	//	CDataSetForClassification* pDataSet, int ExampleIndex,
	//	int paraTestLayerAmount,
	//	CSimpleTypeArray<double>& DstConfidenceList, CSimpleTypeArray<int>& DstPredictionList, CSimpleTypeArray<int>& DstExitLayerList
	//	);
	//void Test(
	//	CDataSetForBinaryClassification* pDataSet,
	//	int paraTestLayerAmount, double paraTestSampleRate,
	//	vector<CDetailedBinaryCascadeClassifyResult>& resRgDetailedResult
	//	);
};

